package org.imraniqbal.pacman;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.Timer;

import org.imraniqbal.engine.Direction;
import org.imraniqbal.engine.Game;
import org.imraniqbal.engine.GameEvent;
import org.imraniqbal.engine.GameListener;
import org.imraniqbal.engine.Map;
import org.imraniqbal.engine.Mappable;
import org.imraniqbal.engine.Player;

/**
 * @author  imran
 */
public class Pacman extends Player implements ActionListener, GameListener {
	
	/**
	 * @uml.property  name="state"
	 * @uml.associationEnd  
	 */
	private PacmanState state;
	private Timer beastTimer;
	/**
	 * Creates a pacman at specified X and Y
	 * @param x X coordinate of pacman
	 * @param y Y coordinate of pacman
	 * @author imran
	 */
	public Pacman(int x, int y) {
		super(x, y);
		initializeTimer();
		setState(PacmanState.NORMAL);
	}
	/**Y
	 * Creates a pacman at specified x and y, with specified direction and lives
	 * @param x X coordinate of pacman
	 * @param y Y coordinate of pacman
	 * @param direction direction from the enum Direction
	 * @param numOflives number of lives you wish pacman to have
	 */
	public Pacman(int x, int y, Direction direction, int numOflives) {
		super(x, y, direction, numOflives);
		initializeTimer();
		setState(PacmanState.NORMAL);
	}

	private void initializeTimer(){
		beastTimer = new Timer(5000, this);
		beastTimer.stop();
	}
	/**
	 * Sets pacman state to specied state, starts beastmode timer if necessary
	 * @param state  Should be of the enum type PacmanState
	 * @author  imran
	 * @uml.property  name="state"
	 */
	public void setState(PacmanState state) {
		this.state = state;
		if( state == PacmanState.BEASTMODE){ 
			beastTimer.stop();				  //stop any previous timer that may have been running
			beastTimer.start(); 
		}
	}
	/**
	 * @return  Pacmans current state
	 * @author  imran
	 * @uml.property  name="state"
	 */
	public PacmanState getState() {
		return state;
	}
	/**
	 * Spawns Pacman at start position
	 * @author imran
	 */
	@Override
	public void spawn(Map map) {
		setX(9);
		setY(9);
		map.addMappable(this);
	}
	/**
	 * @author imran
	 */
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Pacman){
			if(((Pacman)obj).getX() == this.getX() && ((Pacman)obj).getY() == this.getY()){
				return( ((Pacman)obj).getDirection() == this.getDirection() &&
						((Pacman)obj).getNumOflives() == this.getNumOflives());
			}
		}
		return false;
	}
	/**
	 * This is when the timer ends, so pacman's state goes back to normal
	 * @author imran
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		beastTimer.stop();
		this.setState(PacmanState.NORMAL);
	}
	/**
	 *  Pacman does necessary action based on event
	 *  @author imran
	 */
	@Override
	public void onEvent(GameEvent e) {
		if(!(e.getSource() instanceof Game)){ return; }
		Game g = (Game) e.getSource();
		Vector<Mappable> m = g.getMap().getMappable(getX(), getY());
		if(m == null){
			return;
		}
		for(int i = 0; i < m.size(); i++){
			Mappable mpl = m.get(i);
			if( mpl instanceof Ghost){
				if(this.getState() == PacmanState.NORMAL){
					this.die(g.getMap());
					if(getNumOflives() == 0){
						g.setWin(false);
					}
				}
			}
			else if( mpl instanceof BigPill){
				((BigPill)mpl).action(this, g.getMap());
			}else if( mpl instanceof LittlePill){
				((LittlePill)mpl).action(g, g.getMap());
			}
			
		}
		
		//Collision code for tile based games, dealing with things switching spots
		//(this would never be a problem in a non-tile based game)
		
		//universal checking code
		m = g.getMap().getMappable(getOldX(), getOldY());
		if(m == null){ return; }
		for(Mappable mpl : m){
			if( !(mpl instanceof Player) ) { continue; }
			if(((Player)mpl).getOldX() == this.getX() &&
				((Player)mpl).getOldY() == this.getY() ){
				//game specific rule set code below
				if(this.getState() == PacmanState.NORMAL){
					this.die(g.getMap());
					if(getNumOflives() == 0){
						g.setWin(false);
					}
				}
			}
		}
	}
}
